﻿/**** Git Credential Manager for Windows ****
 *
 * Copyright (c) Microsoft Corporation
 * All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the """"Software""""), to deal
 * in the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
**/

using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace Microsoft.Alm
{
    internal static class NativeMethods
    {
        public const string ConsoleInName = "CONIN$";
        public const string ConsoleOutName = "CONOUT$";

        private const string Advapi32 = "advapi32.dll";
        private const string CredUi32 = "credui.dll";
        private const string Kernel32 = "kernel32.dll";

        [Flags]
        public enum ConsoleMode : uint
        {
            /// <summary>
            /// CTRL+C is processed by the system and is not placed in the input buffer.
            /// <para/>
            /// If the input buffer is being read by `<see cref="ReadConsole(SafeFileHandle, StringBuilder, uint, out uint, IntPtr)"/>`, other control keys are processed by the system and are not returned in the ReadConsole buffer.
            /// <para/>
            /// If the <see cref="LineInput"/> mode is also enabled, backspace, carriage return, and line feed characters are handled by the system.
            /// </summary>
            ProcessedInput = 0x0001,

            /// <summary>
            /// The `<see cref="ReadConsole(SafeFileHandle, StringBuilder, uint, out uint, IntPtr)"/>` function returns only when a carriage return character is read.
            /// <para/>
            /// If this mode is disabled, the functions return when one or more characters are available.
            /// </summary>
            LineInput = 0x0002,

            /// <summary>
            /// Characters read by the `<see cref="ReadConsole(SafeFileHandle, StringBuilder, uint, out uint, IntPtr)"/>` function are written to the active screen buffer as they are read.
            /// <para/>
            /// This mode can be used only if the <see cref="LineInput"/> mode is also enabled.
            /// </summary>
            EchoInput = 0x0004,

            /// <summary>
            /// User interactions that change the size of the console screen buffer are reported in the console's input buffer.
            /// <para/>
            /// Information about these events can be read from the input buffer by applications using the ReadConsoleInput function, but not by those using `<see cref="ReadConsole(SafeFileHandle, StringBuilder, uint, out uint, IntPtr)"/>`.
            /// </summary>
            WindowInput = 0x0008,

            /// <summary>
            /// If the mouse pointer is within the borders of the console window and the window has the keyboard focus, mouse events generated by mouse movement and button presses are placed in the input buffer.
            /// <para/>
            /// These events are discarded by `<see cref="ReadConsole(SafeFileHandle, StringBuilder, uint, out uint, IntPtr)"/>`, even when this mode is enabled.
            /// </summary>
            MouseInput = 0x0010,

            /// <summary>
            /// When enabled, text entered in a console window will be inserted at the current cursor location and all text following that location will not be overwritten.
            /// <para/>
            /// When disabled, all following text will be overwritten.
            /// </summary>
            InsertMode = 0x0020,

            /// <summary>
            /// This flag enables the user to use the mouse to select and edit text.
            /// </summary>
            QuickEdit = 0x0040,

            /// <summary>
            /// Characters written by the `<see cref="WriteConsole(SafeHandle, StringBuilder, uint, out uint, IntPtr)"/>` function or echoed by the ReadFile or ReadConsole function are parsed for ASCII control sequences, and the correct action is performed.
            /// <para/>
            /// Backspace, tab, bell, carriage return, and line feed characters are processed.
            /// </summary>
            ProcessedOuput = 0x0001,

            /// <summary>
            /// When writing with `<see cref="WriteConsole(SafeHandle, StringBuilder, uint, out uint, IntPtr)"/>` or echoing with ReadFile or ReadConsole, the cursor moves to the beginning of the next row when it reaches the end of the current row.
            /// <para/>
            /// This causes the rows displayed in the console window to scroll up automatically when the cursor advances beyond the last row in the window.
            /// <para/>
            /// It also causes the contents of the console screen buffer to scroll up (discarding the top row of the console screen buffer) when the cursor advances beyond the last row in the console screen buffer.
            /// <para/>
            /// If this mode is disabled, the last character in the row is overwritten with any subsequent characters.
            /// </summary>
            WrapAtEolOutput = 0x0002,

            AllFlags = ProcessedInput
                     | LineInput
                     | EchoInput
                     | WindowInput
                     | MouseInput
                     | InsertMode
                     | QuickEdit
                     | ProcessedOuput
                     | WrapAtEolOutput,
        }

        [Flags]
        public enum FileAccess : uint
        {
            GenericRead = 0x80000000,

            GenericWrite = 0x40000000,

            GenericExecute = 0x20000000,

            GenericAll = 0x10000000,
        }

        [Flags]
        public enum FileAttributes : uint
        {
            /// <summary>
            /// The file is read only.
            /// <para/>
            /// Applications can read the file, but cannot write to or delete it.
            /// </summary>
            Readonly = 0x00000001,

            /// <summary>
            /// The file is hidden. Do not include it in an ordinary directory listing.
            /// </summary>
            Hidden = 0x00000002,

            /// <summary>
            /// The file is part of or used exclusively by an operating system.
            /// </summary>
            System = 0x00000004,

            Directory = 0x00000010,

            /// <summary>
            /// The file should be archived.
            /// <para/>
            /// Applications use this attribute to mark files for backup
            /// or removal.
            /// </summary>
            Archive = 0x00000020,

            Device = 0x00000040,

            /// <summary>
            /// The file does not have other attributes set. 
            /// <para/>
            /// This attribute is valid only if used alone.
            /// </summary>
            Normal = 0x00000080,

            /// <summary>
            /// The file is being used for temporary storage.
            /// </summary>
            Temporary = 0x00000100,

            SparseFile = 0x00000200,

            ReparsePoint = 0x00000400,

            Compressed = 0x00000800,

            /// <summary>
            /// The data of a file is not immediately available. This attribute indicates that file data is physically moved to offline storage.
            /// <para/>
            /// This attribute is used by Remote Storage, the hierarchical storage management software.
            /// <para/>
            /// Applications should not arbitrarily change this attribute.
            /// </summary>
            Offline = 0x00001000,

            NotContentIndexed = 0x00002000,

            /// <summary>
            /// The file or directory is encrypted.
            /// <para/>For a file, this means that all data in the file is encrypted.
            /// <para/>
            /// For a directory, this means that encryption is the default for newly created files and subdirectories.
            /// <para/>
            /// This flag has no effect if <see cref="Archive"/> is also specified.
            /// <para>
            /// This flag is not supported on Home, Home Premium, Starter, or ARM editions of Windows.
            /// </summary>
            Encrypted = 0x00004000,

            FirstPipeInstance = 0x00080000,

            /// <summary>
            /// The file data is requested, but it should continue to be located in remote storage. 
            /// <para/>
            /// It should not be transported back to local storage.
            /// <para/>
            /// This flag is for use by remote storage systems.
            /// </summary>
            OpenNoRecall = 0x00100000,

            /// <summary>
            /// Normal reparse point processing will not occur; `<see cref="CreateFile(string, FileAccess, FileShare, IntPtr, FileCreationDisposition, FileAttributes, IntPtr)"/>` will attempt to open the reparse point. When a file is opened, a file handle is returned, whether or not the filter that controls the reparse point is operational.
            /// <para/>
            /// This flag cannot be used with the `<see cref="FileCreationDisposition.CreateAlways"/>` flag.
            /// <para/>
            /// If the file is not a reparse point, then this flag is ignored.
            /// </summary>
            OpenReparsePoint = 0x00200000,

            /// <summary>
            /// The file or device is being opened with session awareness.
            /// <para/>
            /// If this flag is not specified, then per-session devices (such as a redirected USB device) cannot be opened by processes running in session 0.
            /// <para/>
            /// This flag has no effect for callers not in session 0.
            /// <para/>
            /// This flag is supported only on server editions of Windows.
            /// </summary>
            SessionAware = 0x00800000,

            /// <summary>
            /// Access will occur according to POSIX rules.
            /// <para/>
            /// This includes allowing multiple files with names, differing only in case, for file systems that support that naming.
            /// <para/>
            /// Use care when using this option, because files created with this flag may not be accessible by applications that are written for MS-DOS or 16-bit Windows.
            /// </summary>
            PosixSemantics = 0x01000000,

            /// <summary>
            /// The file is being opened or created for a backup or restore operation.
            /// <para/>
            /// The system ensures that the calling process overrides file security checks when the process has SE_BACKUP_NAME and SE_RESTORE_NAME privileges.
            /// <para/>
            /// You must set this flag to obtain a handle to a directory.
            /// <para/>
            /// A directory handle can be passed to some functions instead of a file handle.
            /// </summary>
            BackupSemantics = 0x02000000,

            /// <summary>
            /// The file is to be deleted immediately after all of its handles are closed, which includes the specified handle and any other open or duplicated handles.
            /// <para/>
            /// If there are existing open handles to a file, the call fails unless they were all opened with the `<see cref="FileShare.Delete"/>` share mode.
            /// <para/>
            /// Subsequent open requests for the file fail, unless the `<see cref="FileShare.Delete"/>` share mode is specified.
            /// </summary>
            DeleteOnClose = 0x04000000,

            /// <summary>
            /// Access is intended to be sequential from beginning to end. The system can use this as a hint to optimize file caching.
            /// <para/>
            /// This flag should not be used if read-behind (that is, reverse scans) will be used.
            /// <para/>
            /// This flag has no effect if the file system does not support cached I/O and `<see cref="NoBuffering"/>`.
            /// </summary>
            SequentialScan = 0x08000000,

            /// <summary>
            /// Access is intended to be random. The system can use this as a hint to optimize file caching.
            /// <para/>
            /// This flag has no effect if the file system does not support cached I/O and `<see cref="NoBuffering"/>`.
            /// </summary>
            RandomAccess = 0x10000000,

            /// <summary>
            /// The file or device is being opened with no system caching for data reads and writes.
            /// <para/>
            /// This flag does not affect hard disk caching or memory mapped files.
            /// <para/>
            /// There are strict requirements for successfully working with files opened with `<see cref="CreateFile(string, FileAccess, FileShare, IntPtr, FileCreationDisposition, FileAttributes, IntPtr)"/>` using the `<see cref="NoBuffering"/>` flag.
            /// </summary>
            NoBuffering = 0x20000000,

            /// <summary>
            /// The file or device is being opened or created for asynchronous I/O.
            /// <para/>
            /// When subsequent I/O operations are completed on this handle, the event specified in the OVERLAPPED structure will be set to the signaled state.
            /// <para/>
            /// If this flag is specified, the file can be used for simultaneous read and write operations.
            /// <para/>
            /// If this flag is not specified, then I/O operations are serialized, even if the calls to the read and write functions specify an OVERLAPPED structure.
            /// </summary>
            Overlapped = 0x40000000,

            /// <summary>
            /// Write operations will not go through any intermediate cache, they will go directly to disk.
            /// </summary>
            WriteThrough = 0x80000000,
        }

        public enum FileCreationDisposition : uint
        {
            /// <summary>
            /// Creates a new file, only if it does not already exist.
            /// <para/>
            /// If the specified file exists, the function fails and the last-error code is set to <see cref="Win32Error.FileExists"/>.
            /// <para/>
            /// If the specified file does not exist and is a valid path to a writable location, a new file is created.
            /// </summary>
            New = 1,

            /// <summary>
            /// Creates a new file, always.
            /// <para/>
            /// If the specified file exists and is writable, the function overwrites the file, the function succeeds, and last-error code is set to <see cref="Win32Error.AlreadExists"/>.
            /// <para/>
            /// If the specified file does not exist and is a valid path, a new file is created, the function succeeds, and the last-error code is set to zero.
            /// </summary>
            CreateAlways = 2,

            /// <summary>
            /// Opens a file, always.
            /// <para/>
            /// If the specified file exists, the function succeeds and the last-error code is set to <see cref="Win32Error.AlreadExists"/>.
            /// <para/>
            /// If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero.
            /// </summary>
            OpenExisting = 3,

            /// <summary>
            /// Opens a file or device, only if it exists.
            /// <para/>
            /// If the specified file or device does not exist, the function fails and the last-error code is set to <see cref="Win32Error.FileNotFound"/>.
            /// </summary>
            OpenAlways = 4,

            /// <summary>
            /// Opens a file and truncates it so that its size is zero bytes, only if it exists.
            /// <para/>
            /// If the specified file does not exist, the function fails and the last-error code is
            /// set to <see cref="Win32Error.FileNotFound"/>.
            /// <para/>
            /// The calling process must open the file with <see cref="FileAccess.GenericWrite"/>.
            /// </summary>
            TruncateExisting = 5
        }

        [Flags]
        public enum FileShare : uint
        {
            /// <summary>
            /// Prevents other processes from opening a file or device if they request delete, read, or write access.
            /// </summary>
            None = 0x00000000,

            /// <summary>
            /// Enables subsequent open operations on an object to request read access.
            /// <para/>
            /// Otherwise, other processes cannot open the object if they request read access.
            /// <para/>
            /// If this flag is not specified, but the object has been opened for read access, the function fails.
            /// </summary>
            Read = 0x00000001,

            /// <summary>
            /// Enables subsequent open operations on an object to request write access.
            /// <para/>
            /// Otherwise, other processes cannot open the object if they request write access.
            /// <para/>
            /// If this flag is not specified, but the object has been opened for write access, the
            /// function fails.
            /// </summary>
            Write = 0x00000002,

            /// <summary>
            /// Enables subsequent open operations on an object to request delete access.
            /// <para/>
            /// Otherwise, other processes cannot open the object if they request delete access.
            /// <para/>
            /// If this flag is not specified, but the object has been opened for delete access, the function fails.
            /// </summary>
            Delete = 0x00000004
        }

        public enum FileType : uint
        {
            /// <summary>
            /// Either the type of the specified file is unknown, or the function failed.
            /// </summary>
            Unknown = 0x0000,

            /// <summary>
            /// The specified file is a disk file.
            /// </summary>
            Disk = 0x0001,

            /// <summary>
            /// The specified file is a character file, typically an LPT device or a console.
            /// </summary>
            Char = 0x0002,

            /// <summary>
            /// The specified file is a socket, a named pipe, or an anonymous pipe.
            /// </summary>
            Pipe = 0x0003,

            /// <summary>
            /// Unused.
            /// </summary>
            Remote = 0x8000,
        };

        public enum StandardHandleType : int
        {
            /// <summary>
            /// The standard input device. Initially, this is the console input buffer, CONIN$.
            /// </summary>
            Input = -10,

            /// <summary>
            /// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
            /// </summary>
            Output = -11,

            /// <summary>
            /// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
            /// </summary>
            Error = -12
        };

        [Flags]
        public enum CredentialPackFlags : uint
        {
            None = 0,

            ProtectedCredentials = 0x1,

            WowBuffer = 0x2,

            GenericCredentials = 0x4,
        }

        internal enum CredentialType : uint
        {
            /// <summary> 
            /// The `<see cref="Credential"/>` is a generic credential.
            /// <para/>
            /// The credential will not be used by any particular authentication package.
            /// <para/>
            /// The credential will be stored securely but has no other significant characteristics.
            /// </summary>
            Generic = 0x01,

            /// <summary>
            /// The ` <see cref="Credential"/>` is a password credential and is specific to Microsoft's authentication packages.
            /// <para/>
            /// The NTLM, Kerberos, and Negotiate authentication packages will automatically use this credential when connecting to the named target.
            /// </summary>
            DomainPassword = 0x02,

            /// <summary>
            /// The ` <see cref="Credential"/>` is a certificate credential and is specific to Microsoft's authentication packages.
            /// <para/>
            /// The Kerberos, Negotiate, and SChannel authentication packages automatically use this credential when connecting to the named target.
            /// </summary>
            DomainCertificate = 0x03,

            /// <summary>
            /// The ` <see cref="Credential"/>` is a password credential and is specific to authentication packages from Microsoft.
            /// <para/>
            /// The Passport authentication package will automatically use this credential when connecting to the named target.
            /// </summary>
            [Obsolete("This value is no longer supported", true)]
            DomainVisiblePassword = 0x04,

            /// <summary>
            /// The ` <see cref="Credential"/>` is a certificate credential that is a generic authentication package.
            /// </summary>
            GenericCertificate = 0x05,

            /// <summary>
            /// The ` <see cref="Credential"/>` is supported by extended Negotiate packages.
            /// </summary>
            /// <remarks>
            /// Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported.
            /// </remarks>
            DomainExtended = 0x06,

            /// <summary>
            /// The maximum number of supported credential types.
            /// </summary>
            /// <remarks> Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported. </remarks>
            Maximum = 0x07,

            /// <summary>
            /// The extended maximum number of supported credential types that now allow new applications to run on older operating systems.
            /// </summary>
            /// <remarks>
            /// Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported.
            /// </remarks>
            MaximumEx = Maximum + 1000
        }

        [Flags]
        public enum CredentialUiFlags : uint
        {
            None = 0,

            IncorrectPassword = 0x1,

            DoNoPersist = 0x2,

            EquestAdministrator = 0x4,

            ExcludeCertificates = 0x8,

            RequireCertificates = 0x10,

            ShowSaveCheckbox = 0x40,

            AlwaysShowUi = 0x80,

            RequireSmartCard = 0x100,

            PasswordOnlyOk = 0x200,

            ValidateUsername = 0x400,

            CompleteUsername = 0x800,

            Persist = 0x1000,

            ServerCredential = 0x4000,

            ExpectConfermatino = 0x20000,

            GenericCredentals = 0x40000,

            UsernameTargetCredentials = 0x80000,

            KeepUsername = 0x100000,
        }

        public enum CredentialUiResult : uint
        {
            Success = 0,

            Cancelled = 1223,

            NoSuchLogonSession = 1312,

            NotFound = 1168,

            InvalidAccountName = 1315,

            InsufficientBuffer = 122,

            InvalidParameter = 87,

            InvalidFlags = 1004,
        }

        [Flags]
        public enum CredentialUiWindowsFlags : uint
        {
            None = 0,

            /// <summary>
            /// The caller is requesting that the credential provider return the user name and password in plain text.
            /// </summary>
            Generic = 0x0001,

            /// <summary>
            /// The Save check box is displayed in the dialog box.
            /// </summary>
            Checkbox = 0x0002,

            /// <summary>
            /// Only credential providers that support the authentication package specified by the `authPackage` parameter should be enumerated.
            /// </summary>
            AuthPackageOnly = 0x0010,

            /// <summary>
            /// Only the credentials specified by the `inAuthBuffer` parameter for the authentication package specified by the `authPackage` parameter should be enumerated.
            /// <para/>
            /// If this flag is set, and the `inAuthBuffer` parameter is `null`, the function fails.
            /// </summary>
            InCredOnly = 0x0020,

            /// <summary>
            /// Credential providers should enumerate only administrators.
            /// <para/>
            /// This value is intended for User Account Control (UAC) purposes only.
            /// <para/>
            /// We recommend that external callers not set this flag.
            /// </summary>
            EnumerateAdmins = 0x0100,

            /// <summary>
            /// Only the incoming credentials for the authentication package specified by the `authPackage` parameter should be enumerated.
            /// </summary>
            EnumerateCurrentUser = 0x0200,

            /// <summary>
            /// The credential dialog box should be displayed on the secure desktop.
            /// <para/>
            /// This value cannot be combined with <see cref="Generic"/>.
            /// </summary>
            SecurePrompt = 0x1000,

            /// <summary>
            /// The credential dialog box is invoked by the SspiPromptForCredentials function, and the client is prompted before a prior handshake.
            /// <para/>
            /// If SSPIPFC_NO_CHECKBOX is passed in the `inAuthBuffer` parameter, then the credential provider should not display the check box.
            /// </summary>
            Preprompting = 0x2000,

            /// <summary>
            /// The credential provider should align the credential BLOB pointed to by the `outAuthBuffer` parameter to a 32-bit boundary, even if the provider is running on a 64-bit system.
            /// </summary>
            Pack32Wow = 0x10000000,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public unsafe struct CredentialUiInfo
        {
            [MarshalAs(UnmanagedType.U4)]
            public int Size;

            [MarshalAs(UnmanagedType.SysInt)]
            public IntPtr Parent;

            [MarshalAs(UnmanagedType.LPWStr)]
            public string MessageText;

            [MarshalAs(UnmanagedType.LPWStr)]
            public string CaptionText;

            [MarshalAs(UnmanagedType.SysInt)]
            public IntPtr BannerArt;
        }

        /// <summary> Creates and displays a configurable dialog box that accepts credentials
        /// information from a user. </summary> <param name="credUiInfo">A pointer to a <see
        /// cref="CredentialUiInfo"/> structure that contains information for customizing the
        /// appearance of the dialog box</param> <param name="targetName">A pointer to a
        /// null-terminated string that contains the name of the target for the credentials,
        /// typically a server name. For Distributed File System (DFS) connections, this string is of
        /// the form ServerName\ShareName. This parameter is used to identify target information when
        /// storing and retrieving credentials.</param> <param name="reserved">This parameter is
        /// reserved for future use. It must be NUL</param> <param name="authError">Specifies why the
        /// credential dialog box is needed. A caller can pass this Windows error parameter, returned
        /// by another authentication call, to allow the dialog box to accommodate certain errors.
        /// For example, if the password expired status code is passed, the dialog box could prompt
        /// the user to change the password on the account.</param> <param name="username"> <para>A
        /// pointer to a null-terminated string that contains the user name for the credentials. If a
        /// nonzero-length string is passed, the <paramref name="username"/> option of the dialog box
        /// is prefilled with the string.</param> <param name="usernameMaxLen">The maximum number of
        /// characters that can be copied to <paramref name="username"/> including the terminating
        /// null character.</param> <param name="password"> <para>A pointer to a null-terminated
        /// string that contains the password for the credentials. If a nonzero-length string is
        /// specified for <paramref name="password"/>, the password option of the dialog box will be
        /// prefilled with the string.</para> </param> <param name="passwordMaxLen">he maximum number
        /// of characters that can be copied to <paramref name="password"/> including the terminating
        /// null character.</param> <param name="saveCredentials">A pointer to a <langword
        /// name="bool"/> that specifies the initial state of the Save check box and receives the
        /// state of the Save check box after the user has responded to the dialog box. If this value
        /// is not NULL and <see cref="CredUIPromptForCredentials"/> returns <see
        /// cref="CredentialUiResult.Success"/>, then <paramref name="save"/> returns the state of
        /// the Save check box when the user chose OK in the dialog box.</param> <param
        /// name="flags">Specifies special behavior for this function</param> <returns><see cref="CredentialUiResult"/></returns>
        [DllImport(CredUi32, CharSet = CharSet.Unicode, EntryPoint = "CredUIPromptForCredentialsW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.U4)]
        public static extern CredentialUiResult CredUIPromptForCredentials(
            [In, MarshalAs(UnmanagedType.Struct)] ref CredentialUiInfo credUiInfo,
            [In, MarshalAs(UnmanagedType.LPWStr)] string targetName,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr reserved,
            [In, MarshalAs(UnmanagedType.U4)] uint authError,
            [In, MarshalAs(UnmanagedType.LPWStr)] StringBuilder username,
            [In, MarshalAs(UnmanagedType.I4)] int usernameMaxLen,
            [In, MarshalAs(UnmanagedType.LPWStr)] StringBuilder password,
            [In, MarshalAs(UnmanagedType.I4)] int passwordMaxLen,
            [In, MarshalAs(UnmanagedType.Bool)] ref bool saveCredentials,
            [In, MarshalAs(UnmanagedType.U4)] CredentialUiFlags flags);

        /// <summary>
        /// Creates and displays a configurable dialog box that allows users to supply credential information by using any credential provider installed on the local computer.
        /// <para/>
        /// Returns `<see cref="Win32Error"/>` code value on failure; otherwise `<see cref="Win32Error.Success"/>`.
        /// </summary>
        /// <param name="credInfo">
        /// A pointer to a `<see cref="CredentialUiInfo"/>` structure that contains information for customizing the appearance of the dialog box that this function displays.
        /// <para/>
        /// If the hwndParent member of the `<see cref="CredentialUiInfo"/>` structure is not `<see langword="null"/>`, this function displays a modal dialog box centered on the parent window.
        /// <para/>
        /// If the hwndParent member of the `<see cref="CredentialUiInfo"/>` structure is `<see langword="null"/>`, the function displays a dialog box centered on the screen.
        /// <para/>
        /// This function ignores the `<see cref="CredentialUiInfo.BannerArt"/>` member of the `<see cref="CredentialUiInfo"/>` structure.
        /// </param>
        /// <param name="authError">
        /// A Windows error code, defined in Winerror.h, that is displayed in the dialog box.
        /// <para/>
        /// If credentials previously collected were not valid, the caller uses this parameter to pass the error message from the API that collected the credentials (for example, Winlogon) to this function.
        /// <para/>
        /// The corresponding error message is formatted and displayed in the dialog box.
        /// <para/>
        /// Set the value of this parameter to zero to display no error message.
        /// </param>
        /// <param name="authPackage">
        /// On input, the value of this parameter is used to specify the authentication package for which the credentials in the `<paramref name="inAuthBuffer"/>` buffer are serialized.
        /// If the value of `<paramref name="inAuthBuffer"/>` is `null` and the `<see cref="CredentialUiWindowsFlags.AuthPackageOnly"/>` flag is set in the `<paramref name="flgs"/>` parameter, only credential providers capable of serializing credentials for the specified authentication package are to be enumerated.
        /// <para/>
        /// To get the appropriate value to use for this parameter on input, call the  `LsaLookupAuthenticationPackage` function and use the value of the `<paramref name="authPackage"/>` parameter of that function.
        /// <para/>
        /// On output, this parameter specifies the authentication package for which the credentials in the <paramref name="outAuthBuffer"/> buffer are serialized.
        /// </param>
        /// <param name="inAuthBuffer">
        /// A pointer to a credential BLOB that is used to populate the credential fields in the dialog box. Set the value of this parameter to `<see langword="null"/>` to leave the credential fields empty.
        /// </param>
        /// <param name="inAuthBufferSize">The size, in bytes, of the pvInAuthBuffer buffer.</param>
        /// <param name="outAuthBuffer">
        /// <para>
        /// The address of a pointer that, on output, specifies the credential BLOB.
        /// <para/>
        /// For Kerberos, NTLM, or Negotiate credentials, call the `CredUnPackAuthenticationBuffer` function to convert this BLOB to string representations of the credentials.
        /// </para>
        /// <para>
        /// When you have finished using the credential BLOB, clear it from memory by calling the SecureZeroMemory function, and free it by calling the CoTaskMemFree function.
        /// </para>
        /// </param>
        /// <param name="outAuthBufferSize">The size, in bytes, of the `<paramref name="outAuthBuffer"/>` buffer.</param>
        /// <param name="saveCredentials">
        /// A pointer to a `<see langword="bool"/>` value that, on input, specifies whether the Save check box is selected in the dialog box that this function displays.
        /// <para/>
        /// On output, the value of this parameter specifies whether the Save check box was selected when the user clicks the Submit button in the dialog box.
        /// <para/>
        /// Set this parameter to `<see langword="null"/>` to ignore the Save check box.
        /// <para/>
        /// This parameter is ignored if the `CREDUIWIN_CHECKBOX` flag is not set in the dwFlags parameter.
        /// </param>
        /// <param name="flags">A value that specifies behavior for this function.</param>
        [DllImport(CredUi32, CharSet = CharSet.Unicode, EntryPoint = "CredUIPromptForWindowsCredentialsW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.I4)]
        public static extern int CredUIPromptForWindowsCredentials(
            [In, MarshalAs(UnmanagedType.Struct)] ref CredentialUiInfo credInfo,
            [In, MarshalAs(UnmanagedType.U4)] uint authError,
            [In, Out, MarshalAs(UnmanagedType.U4)] ref CredentialPackFlags authPackage,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr inAuthBuffer,
            [In, MarshalAs(UnmanagedType.U4)] uint inAuthBufferSize,
            [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr outAuthBuffer,
            [Out, MarshalAs(UnmanagedType.U4)] out uint outAuthBufferSize,
            [In, MarshalAs(UnmanagedType.Bool)] ref bool saveCredentials,
            [In, MarshalAs(UnmanagedType.U4)] CredentialUiWindowsFlags flags);

        /// <summary>
        /// Converts a string user name and password into an authentication buffer.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="flags">
        /// Specifies how the credential should be packed. This can be a combination of the following flags.
        /// </param>
        /// <param name="username">
        /// A pointer to a null-terminated string that specifies the user name to be converted.
        /// </param>
        /// <param name="password">
        /// A pointer to a null-terminated string that specifies the password to be converted.
        /// </param>
        /// <param name="packedCredentials">
        /// A pointer to an array of bytes that, on output, receives the packed authentication buffer.
        /// <para/>
        /// This parameter can be `<see langword="null"/>` to receive the required buffer size in the
        /// <paramref name="packedCredentialsSize"/> parameter.
        /// </param>
        /// <param name="packedCredentialsSize">
        /// A pointer to a `DWORD` value that specifies the size, in bytes, of the
        /// <paramref name="packedCredentials"/> buffer. On output, if the buffer is not of
        /// sufficient size, specifies the required size, in bytes, of the
        /// <paramref name="packedCredentials"/> buffer.
        /// </param>
        [DllImport(CredUi32, CharSet = CharSet.Unicode, EntryPoint = "CredPackAuthenticationBufferW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CredPackAuthenticationBuffer(
            [In, MarshalAs(UnmanagedType.U4)] CredentialPackFlags flags,
            [In, MarshalAs(UnmanagedType.LPWStr)] string username,
            [In, MarshalAs(UnmanagedType.LPWStr)] string password,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr packedCredentials,
            [In, MarshalAs(UnmanagedType.I4)] ref int packedCredentialsSize);

        /// <summary>
        /// Converts an authentication buffer returned by a call to the `<see cref="CredUIPromptForWindowsCredentials"/>` function into a string user name and password.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="flags">
        /// Setting the value of this parameter to `CRED_PACK_PROTECTED_CREDENTIALS` specifies that the function attempts to decrypt the credentials in the authentication buffer.
        /// <para/>
        /// If the credential cannot be decrypted, the function returns `false`, and a call to the `GetLastError` function will return the value `<see cref="Win32Error.NotCapable"/>`.
        /// <para/>
        /// How the decryption is done depends on the format of the authentication buffer.
        /// <para>
        /// If the authentication buffer is a `SEC_WINNT_AUTH_IDENTITY_EX2` structure, the function can decrypt the buffer if it is encrypted by using `SspiEncryptAuthIdentityEx` with the `SEC_WINNT_AUTH_IDENTITY_ENCRYPT_SAME_LOGON` option.
        /// <para/>
        /// If the authentication buffer is one of the marshaled `KERB_*_LOGON` structures, the function decrypts the password before returning it in the `<paramref name="password"/>` buffer.
        /// </param>
        /// <param name="authBuffer">
        /// A pointer to the authentication buffer to be converted.
        /// </param>
        /// <param name="authBufferSize">
        /// The size, in bytes, of the pAuthBuffer buffer.
        /// </param>
        /// <param name="username">
        /// A pointer to a null-terminated string that receives the user name.
        /// </param>
        /// <param name="maxUsernameLen">
        /// A pointer to a DWORD value that specifies the size, in characters, of the `<paramref name="username"/>` buffer.
        /// <para/>
        /// On output, if the buffer is not of sufficient size, specifies the required size, in characters, of the `<paramref name="username"/>` buffer.
        /// <para/>
        /// The size includes terminating `<see langword="null"/>` character.
        /// </param>
        /// <param name="domainName">
        /// A pointer to a null-terminated string that receives the name of the user's domain.
        /// </param>
        /// <param name="maxDomainNameLen">
        /// pointer to a `DWORD` value that specifies the size, in characters, of the `<paramref name="domainName"/>` buffer.
        /// <para/>
        /// On output, if the buffer is not of sufficient size, specifies the required size, in characters, of the `<paramref name="domainName"/>` buffer.
        /// <para/>
        /// The size includes the terminating `<see langword="null"/>` character.
        /// <para/>
        /// The required size can be zero if there is no domain name.
        /// </param>
        /// <param name="password">
        /// A pointer to a null-terminated string that receives the password.
        /// </param>
        /// <param name="maxPasswordLen">
        /// A pointer to a `DWORD` value that specifies the size, in characters, of the `<paramref name="password"/>` buffer.
        /// <para/>
        /// On output, if the buffer is not of sufficient size, specifies the required size, in characters, of the `<paramref name="password"/>` buffer.
        /// <para/>
        /// The size includes the terminating `<see langword="null"/>` character.
        /// </param>
        [DllImport(CredUi32, CharSet = CharSet.Unicode, EntryPoint = "CredUnPackAuthenticationBufferW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CredUnPackAuthenticationBuffer(
            [In, MarshalAs(UnmanagedType.U4)] CredentialPackFlags flags,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr authBuffer,
            [In, MarshalAs(UnmanagedType.U4)] uint authBufferSize,
            [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder username,
            [In, Out, MarshalAs(UnmanagedType.I4)] ref int maxUsernameLen,
            [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder domainName,
            [In, Out, MarshalAs(UnmanagedType.I4)] ref int maxDomainNameLen,
            [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder password,
            [In, Out, MarshalAs(UnmanagedType.I4)] ref int maxPasswordLen);

        /// <summary>
        /// Creates or opens a file or I/O device.
        /// <para/>
        /// The most commonly used I/O devices are as follows: file, file stream, directory, physical disk, volume, console buffer, tape drive, communications resource, mailslot, and pipe.
        /// <para/>
        /// The function returns a handle that can be used to access the file or device for various types of I/O depending on the file or device and the flags and attributes specified.
        /// <para/>
        /// Return a handle to the file created.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file or device to be created or opened. You may use either forward slashes (/) or backslashes (\) in this name.
        /// <para/>
        /// In the ANSI version of this function, the name is limited to `MAX_PATH` characters.
        /// <para/>
        /// To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.
        /// </param>
        /// <param name="desiredAccess">
        /// The requested access to the file or device, which can be summarized as read, write, both or neither zero).
        /// <para/>
        /// If this parameter is zero, the application can query certain metadata such as file, directory, or device attributes without accessing that file or device, even if `<see cref="FileAccess.GenericRead"/>` access would have been denied.
        /// <para/>
        /// You cannot request an access mode that conflicts with the sharing mode that is specified by the `<paramref name="sharedMode"/>` parameter in an open request that already has an open handle.
        /// </param>
        /// <param name="shareMode">
        /// The requested sharing mode of the file or device, which can be read, write, both, delete, all of these, or none (refer to the following table).
        /// <para/>
        /// Access requests to attributes or extended attributes are not affected by this flag.
        /// <para/>
        /// If this parameter is zero and CreateFile succeeds, the file or device cannot be shared and cannot be opened again until the handle to the file or device is closed.
        /// <para/>
        /// You cannot request a sharing mode that conflicts with the access mode that is specified in an existing request that has an open handle.
        /// <para/>
        /// CreateFile would fail and the `<see cref="Marshal.GetLastWin32Error"/>` function would return `<see cref="Win32Error.SharingViloation"/>`.
        /// <para/>
        /// To enable a process to share a file or device while another process has the file or device open, use a compatible combination of one or more of the following values.
        /// </param>
        /// <param name="securityAttributes">
        /// This parameter should be `<see cref="IntPtr.Zero"/>`.
        /// </param>
        /// <param name="creationDisposition">
        /// An action to take on a file or device that exists or does not exist.
        /// <para/>
        /// For devices other than files, this parameter is usually set to `<see cref="FileCreationDisposition.OpenExisting"/>`.
        /// </param>
        /// <param name="flagsAndAttributes">
        /// The file or device attributes and flags, `<see cref="FileAttributes.Normal"/>` being the most common default value for files.
        /// <para/>
        /// This parameter can include any combination of `<see cref="FileAttributes"/>`.
        /// <para/>
        /// All other file attributes override `<see cref="FileAttributes.Normal"/>`.
        /// </param>
        /// <param name="templateFile">
        /// This parameter should be <`see cref="IntPtr.Zero"/>`.
        /// </param>
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "CreateFileW", SetLastError = true)]
        public static extern SafeFileHandle CreateFile(
            [In, MarshalAs(UnmanagedType.LPWStr)] string fileName,
            [In, MarshalAs(UnmanagedType.U4)] FileAccess desiredAccess,
            [In, MarshalAs(UnmanagedType.U4)] FileShare shareMode,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr securityAttributes,
            [In, MarshalAs(UnmanagedType.U4)] FileCreationDisposition creationDisposition,
            [In, MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr templateFile);

        /// <summary>
        /// Retrieves the current input mode of a console's input buffer or the current output mode of a console screen buffer.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="consoleHandle">
        /// A handle to the console input buffer or the console screen buffer. The handle must have the <see cref="FileAccess.GenericRead"/> access right.
        /// </param>
        /// <param name="consoleMode">
        /// A pointer to a variable that receives the current mode of the specified buffer.
        /// <para/>
        /// If the `<paramref name="consoleHandle"/>` parameter is an input handle, the mode can be one or more of the following values.
        /// <para/>
        /// When a console is created, all input modes except `<see cref="ConsoleMode.WindowInput"/>` are enabled by default.
        /// <para/>
        /// If the `<paramref name="consoleHandle"/>` parameter is a screen buffer handle, the mode can be one or more of the following values.
        /// <para/>
        /// When a screen buffer is created, both output modes are enabled by default.
        /// </param>
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "GetConsoleMode", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetConsoleMode(
            [In] SafeFileHandle consoleHandle,
            [Out, MarshalAs(UnmanagedType.U4)] out ConsoleMode consoleMode);

        /// <summary>
        /// Retrieves the file type of the specified file.
        /// <para/>
        /// Returns a `<see cref="FileType"/>`.
        /// </summary>
        /// <param name="fileHandle">A handle to the file.</param>
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "GetFileType", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.U4)]
        public static extern FileType GetFileType(
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr fileHandle);

        /// <summary>
        /// Retrieves a handle to the specified standard device (standard input, standard output, or standard error).
        /// <para/>
        /// Returns a handle to the requested pipe.
        /// </summary>
        /// <param name="std">The type of the requested standard pipe.</param>
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "GetStdHandle", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.SysInt)]
        public static extern IntPtr GetStdHandle(
            [In, MarshalAs(UnmanagedType.I4)] StandardHandleType std);

        /// <summary>
        /// Reads character input from the console input buffer and removes it from the buffer.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="consoleInputHandle">
        /// A handle to the console input buffer. The handle must have the `<see cref="FileAccess.GenericRead"/>` access right.
        /// </param>
        /// <param name="buffer">
        /// A pointer to a buffer that receives the data read from the console input buffer.
        /// <para/>
        /// The storage for this buffer is allocated from a shared heap for the process that is 64 KB in size.
        /// <para/>
        /// The maximum size of the buffer will depend on heap usage.
        /// </param>
        /// <param name="numberOfCharsToRead">
        /// The number of characters to be read.
        /// <para/>
        /// The size of the buffer pointed to by the `<paramref name="buffer"/>` parameter should be at least `<paramref name="NumberofCharsToRead"/>` * `<see langword="sizeof"/>(<see langword="char"/>)` bytes.
        /// </param>
        /// <param name="numberOfCharsRead">
        /// A pointer to a variable that receives the number of characters actually read.
        /// </param>
        /// <param name="reserved">
        /// Reserved; must be `<see cref="IntPtr.Zero"/>`.
        /// </param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api")]
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "ReadConsoleW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ReadConsole(
            [In] SafeFileHandle consoleInputHandle,
            [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer,
            [In, MarshalAs(UnmanagedType.U4)] uint numberOfCharsToRead,
            [Out, MarshalAs(UnmanagedType.U4)] out uint numberOfCharsRead,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr reserved);

        /// <summary>
        /// Sets the input mode of a console's input buffer or the output mode of a console screen buffer.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="consoleHandle">
        /// A handle to the console input buffer or a console screen buffer.
        /// <para/>
        /// The handle must have the `<see cref="FileAccess.GenericRead"/>` access right.
        /// </param>
        /// <param name="consoleMode">
        /// <para>
        /// The input or output mode to be set.
        /// <para/>
        /// If the `<paramref name="consoleHandle"/>` parameter is an input handle, the mode can be one or more of the following values.
        /// <para/>
        /// When a console is created, all input modes except `<see cref="ConsoleMode.WindowInput"/>` are enabled by default.
        /// </para>
        /// <para>
        /// If the `<paramref name="consoleHandle"/>` parameter is a screen buffer handle, the mode can be one or more of the following values.
        /// <para/>
        /// When a screen buffer is created, both output modes are enabled by default.
        /// </para>
        /// </param>
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "SetConsoleMode", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetConsoleMode(
            [In] SafeFileHandle consoleHandle,
            [In, MarshalAs(UnmanagedType.U4)] ConsoleMode consoleMode);

        /// <summary>
        /// Writes a character string to a console screen buffer beginning at the current cursor location.
        /// <para/>
        /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`.
        /// </summary>
        /// <param name="consoleOutputHandle">
        /// A handle to the console screen buffer.
        /// <para/>
        /// The handle must have the `<see cref="FileAccess.GenericWrite"/>` access right.
        /// </param>
        /// <param name="buffer">
        /// A pointer to a buffer that contains characters to be written to the console screen buffer.
        /// <para/>
        /// The storage for this buffer is allocated from a shared heap for the process that is 64 KB in size.
        /// <para/>
        /// The maximum size of the buffer will depend on heap usage.
        /// </param>
        /// <param name="numberOfCharsToWrite">
        /// The number of characters to be written.
        /// <para/>
        /// If the total size of the specified number of characters exceeds the available heap, the function fails with `<see cref="Win32Error.NotEnoughMemory"/>`.
        /// </param>
        /// <param name="numberOfCharsWritten">
        /// A pointer to a variable that receives the number of characters actually written.
        /// </param>
        /// <param name="reserved">
        /// Reserved; must be `<see cref="IntPtr.Zero"/>`.
        /// </param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api")]
        [DllImport(Kernel32, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "WriteConsoleW", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool WriteConsole(
            [In] SafeHandle consoleOutputHandle,
            [In, MarshalAs(UnmanagedType.LPWStr)] StringBuilder buffer,
            [In, MarshalAs(UnmanagedType.U4)] uint numberOfCharsToWrite,
            [Out, MarshalAs(UnmanagedType.U4)] out uint numberOfCharsWritten,
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr reserved);

        /// <summary>
        /// The System Error Codes are very broad.
        /// <para/>
        /// Each one can occur in one of many hundreds of locations in the system.
        /// <para/>
        /// Consequently the descriptions of these codes cannot be very specific.
        /// <para/>
        /// Use of these codes requires some amount of investigation and analysis.
        /// <para/>
        /// You need to note both the programmatic and the run-time context in which these errors occur.
        /// <para/>
        /// Because these codes are defined in WinError.h for anyone to use, sometimes the codes are returned by non-system software.
        /// <para/>
        /// Sometimes the code is returned by a function deep in the stack and far removed from your code that is handling the error.
        /// </summary>
        internal static class Win32Error
        {
            /// <summary>
            /// The operation completed successfully.
            /// </summary>
            public const int Success = 0;
            /// <summary>
            /// The system cannot find the file specified.
            /// </summary>
            public const int FileNotFound = 2;
            /// <summary>
            /// The handle is invalid.
            /// </summary>
            public const int InvalidHandle = 6;
            /// <summary>
            /// Not enough storage is available to process this command.
            /// </summary>
            public const int NotEnoughMemory = 8;
            /// <summary>
            /// A device attached to the system is not functioning.
            /// </summary>
            public const int GenericFailure = 31;
            /// <summary>
            /// The process cannot access the file because it is being used by another process.
            /// </summary>
            public const int SharingViolation = 32;
            /// <summary>
            /// The file exists.
            /// </summary>
            public const int FileExists = 80;
            /// <summary>
            /// The data area passed to a system call is too small.
            /// </summary>
            public const int InsufficientBuffer = 122;
            /// <summary>
            /// Cannot create a file when that file already exists.
            /// </summary>
            public const int AlreadExists = 183;
            /// <summary>
            /// The implementation is not capable of performing the request.
            /// </summary>
            public const int NotCapable = 775;
            /// <summary>
            /// Element not found.
            /// </summary>
            public const int NotFound = 1168;
            /// <summary>
            /// A specified logon session does not exist. It may already have been terminated.
            /// </summary>
            public const int NoSuchLogonSession = 1312;

            public static string GetText(int error)
            {
                switch (error)
                {
                    default:
                        return error.ToString();

                    case 1:
                        return "INVALID_FUNCTION";

                    case AlreadExists:
                        return "ALREADY_EXISTS";

                    case FileExists:
                        return "FILE_EXISTS";

                    case FileNotFound:
                        return "FILE_NOT_FOUND";

                    case GenericFailure:
                        return "GENERIC_FAILURE (" + error + ")";

                    case InsufficientBuffer:
                        return "INSUFFICIENT_BUFFER";

                    case InvalidHandle:
                        return "INVALID_HANDLE";

                    case NoSuchLogonSession:
                        return "NO_SUCH_LOGON_SESSION";

                    case NotCapable:
                        return "NOT_CAPABLE";

                    case NotEnoughMemory:
                        return "NOT_ENOUGH_MEMORY";

                    case NotFound:
                        return "NOT_FOUND";

                    case SharingViolation:
                        return "SHARING_VILOATION";

                    case Success:
                        return "SUCCESS";
                }
            }
        }
    }
}
